package com.zxj.netty.model;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 消费端用来处理远程调用结果
 */
public class DefaultFuture {
    private final static ConcurrentHashMap<Long, DefaultFuture> ALL_FAUTUE = new ConcurrentHashMap<>();

    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    private NettyResponse response;

    static {
        Thread thread = new Thread(new FutrueThread());
        thread.setDaemon(true);
        thread.start();
    }
    /**
     * DefaultFuture有效期90s
     */
    private long timout = 90L * 1000;

    private long startime = System.currentTimeMillis();

    public DefaultFuture(NettyRequest request) {
        ALL_FAUTUE.put(request.getId(), this);
    }

    public NettyResponse get() {
        lock.lock();
        process(timout);
        return this.response;
    }

    private void process(long timout) {
        try {
            while (!done()) {
                condition.await(timout, TimeUnit.SECONDS);

                if ((System.currentTimeMillis() - startime) > timout) {
                    System.out.println("请求处理超时");
                    throw new RuntimeException("请求处理超时");
                }
            }
        } catch (Exception e) {

        } finally {
            lock.unlock();
        }
    }

    public NettyResponse get(long time) {
        lock.lock();
        process(time);
        return this.response;
    }

    // handler解析服务端返回
    public static void receive(NettyResponse response) {
        DefaultFuture defaultFuture = ALL_FAUTUE.get(response.getId());
        if (defaultFuture != null) {
            defaultFuture.lock.lock();

            try {
                defaultFuture.setResponse(response);
                defaultFuture.condition.signal();
                ALL_FAUTUE.remove(response.getId());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                defaultFuture.lock.unlock();
            }
        }
    }

    private boolean done() {
        return this.response != null;
    }

    public void setResponse(NettyResponse response) {
        this.response = response;
    }

    public NettyResponse getResponse() {
        return response;
    }

    public long getTimout() {
        return timout;
    }

    public void setTimout(long timout) {
        this.timout = timout;
    }

    public long getStartime() {
        return startime;
    }

    public void setStartime(long startime) {
        this.startime = startime;
    }


    static class FutrueThread implements Runnable {
        @Override
        public void run() {
            Set<Map.Entry<Long, DefaultFuture>> entries = ALL_FAUTUE.entrySet();

            for (Map.Entry<Long, DefaultFuture> entry : entries) {
                Long key = entry.getKey();
                DefaultFuture value = entry.getValue();
                if (value == null) {
                    ALL_FAUTUE.remove(key);
                } else if ((System.currentTimeMillis() - value.getStartime()) > value.getTimout()) {
                    // 处理超时
                    NettyResponse response = new NettyResponse();
                    response.setId(key);
                    response.setCode("-1");
                    response.setText("处理超时！");
                    receive(response);
                }
            }
        }
    }
}
